package com.ridu.project.beshid.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.ridu.project.beshid.api.GeneralResponse;
import com.ridu.project.beshid.api.JifenReq;
import com.ridu.project.beshid.api.Status;
import com.ridu.project.beshid.config.Global;
import com.ridu.project.beshid.config.GlobalConfiguration;
import com.ridu.project.beshid.entity.*;
import com.ridu.project.beshid.repository.JifenRepository;
import com.ridu.project.beshid.repository.JifenReqRepository;
import com.ridu.project.beshid.repository.JifenStreamRepository;
import com.ridu.project.beshid.repository.UserRepository;
import com.ridu.project.beshid.service.JifenReqService;
import com.ridu.project.beshid.service.JifenService;
import com.ridu.project.beshid.utils.DateUtil;
import com.ridu.project.beshid.utils.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.math.BigDecimal;
import java.util.*;

/**
 * Created by user on 2017/10/18.
 */
@Service
@Slf4j
public class JifenReqServiceImpl implements JifenReqService {

    @Autowired
    private JifenReqRepository repository;
    @Autowired
    private JifenService jifenService;
    @Autowired
    private JifenRepository jifenRepository;
    @Autowired
    private UserRepository userRepository;
    @Autowired
    RestService restService;
    @Autowired
    private GlobalConfiguration globalConfiguration;
    @Autowired
    private JifenStreamRepository jifenStreamRepository;
    @Autowired
    private JifenReqRepository jifenReqRepository;

    @Override
    public GeneralResponse<JifenReq> findAll(int currentPage, int pageSize, String username,String flow,String source,String type,
                                          String startTime, String endTime) {
        GeneralResponse<JifenReq> response = new GeneralResponse<>();
        try {
            if (currentPage == 0) {
                currentPage = 1;
            }
            if (pageSize == 0) {
                pageSize = Global.DEFAULT_PAGE_SIZE;
            }
            Sort sort = new Sort(Sort.Direction.DESC, "id");
            Pageable pageable = new PageRequest(currentPage - 1, pageSize, sort);
            Page<JifenReqEntity> page = repository.findAll(new Specification<JifenReqEntity>() {
                @Override
                public Predicate toPredicate(Root<JifenReqEntity> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                    List<Predicate> queryPredicates = new ArrayList<>();
                    if (!StringUtil.format(startTime).equals("") ||
                            !StringUtil.format(endTime).equals("")) {
                        Date s = DateUtil.parse(startTime);
                        Date e = DateUtil.parse(endTime + " 23:59:59");
                        if (!StringUtil.format(startTime).equals("") &&
                                !StringUtil.format(endTime).equals("")) {
                            queryPredicates.add(cb.between(root.<Date>get("dateCreated"), s, e));
                        } else if (StringUtil.format(startTime).equals("")) {
                            queryPredicates.add(cb.lessThanOrEqualTo(root.<Date>get("dateCreated"), e));
                        } else if (StringUtil.format(endTime).equals("")) {
                            queryPredicates.add(cb.greaterThanOrEqualTo(root.<Date>get("dateCreated"), s));
                        }
                    }
                    if(StringUtils.isNotBlank(flow)){
                        if(flow.equals("in")){
                            queryPredicates.add(cb.ge(root.<BigDecimal>get("req_jifen"), 0));
                        } else if(flow.equals("out")) {
                            queryPredicates.add(cb.lt(root.<BigDecimal>get("req_jifen"), 0));
                        }
                    }
                    if(StringUtils.isNotBlank(username)){
                        queryPredicates.add(cb.equal(root.<Long>get("user").<Long>get("username"), username));
                    }
                    if(StringUtils.isNotBlank(source)){
                        queryPredicates.add(cb.equal(root.<Long>get("user").<String>get("platform"), source));
                    }
                    if(StringUtils.isNotBlank(type)){
                    }
                    queryPredicates.add(cb.or(cb.isNull(root.<String>get("status")), cb.equal(root.<String>get("status"), "")));
                    query.where(queryPredicates.toArray(new Predicate[0]));
                    return null;
                }
            }, pageable);
            List<JifenReqEntity> dataList = page.getContent();
            List<JifenReq> jifens = new ArrayList<>();
            if(CollectionUtils.size(dataList) > 0){
                dataList.stream().forEach(jifenReqEntity -> {
                    JifenReq req = new JifenReq();
                    BeanUtils.copyProperties(jifenReqEntity, req);
                    if(jifenReqEntity.getOwner() != null){
                        req.setMobile(jifenReqEntity.getOwner().getBeshId());
                    }
                    if(jifenReqEntity.getUser_req() != null){
                        req.setMobile(jifenReqEntity.getUser_req().getUsername());
                    }
                    jifens.add(req);
                });
            }
            response.setStatus(Status.SUCCESS);
            response.setRows(jifens);
            response.setTotal(page.getTotalElements());
        } catch (Exception e) {
            response.setStatus(Status.FAILED);
            response.setMessage(e.getMessage());
            log.error("error", e);
        }
        return response;
    }

    @Override
    public GeneralResponse getJifensAuditList(int currentPage, int pageSize, String status) {
        return getJifensAuditList(currentPage, pageSize, null, null, null, null, status);
    }

    @Override
    public GeneralResponse getJifensAuditList(int currentPage, int pageSize, String startTime, String endTime, String username, String platform, String status) {
        GeneralResponse<JifenReq> response = new GeneralResponse<>();
        try {
            if (currentPage == 0) {
                currentPage = 1;
            }
            if (pageSize == 0) {
                pageSize = Global.DEFAULT_PAGE_SIZE;
            }
            Sort sort = new Sort(Sort.Direction.DESC, "id");
            Pageable pageable = new PageRequest(currentPage - 1, pageSize, sort);
            Page<JifenReqEntity> page = repository.findAll(new Specification<JifenReqEntity>() {
                @Override
                public Predicate toPredicate(Root<JifenReqEntity> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
                    List<Predicate> queryPredicates = new ArrayList<>();
                    if (!StringUtil.format(startTime).equals("") ||
                            !StringUtil.format(endTime).equals("")) {
                        Date s = DateUtil.parse(startTime);
                        Date e = DateUtil.parse(endTime + " 23:59:59");
                        if (!StringUtil.format(startTime).equals("") &&
                                !StringUtil.format(endTime).equals("")) {
                            queryPredicates.add(cb.between(root.<Date>get("dateCreated"), s, e));
                        } else if (StringUtil.format(startTime).equals("")) {
                            queryPredicates.add(cb.lessThanOrEqualTo(root.<Date>get("dateCreated"), e));
                        } else if (StringUtil.format(endTime).equals("")) {
                            queryPredicates.add(cb.greaterThanOrEqualTo(root.<Date>get("dateCreated"), s));
                        }
                    }
                    if(StringUtils.isNotBlank(username)){
                        queryPredicates.add(cb.equal(root.<Long>get("user_req").<String>get("username"), username));
                    } else {
                        queryPredicates.add(cb.isNull(root.<Long>get("owner")));
                    }
                    if(StringUtils.isNotBlank(platform)){
                        queryPredicates.add(cb.equal(root.<String>get("platform"), platform));
                    }
                    if(StringUtils.isBlank(status)){
                        queryPredicates.add(cb.or(cb.isNull(root.<String>get("status")), cb.equal(root.<String>get("status"), "")));
                    }
                    query.where(queryPredicates.toArray(new Predicate[0]));
                    return null;
                }
            }, pageable);
            List<JifenReqEntity> dataList = page.getContent();
            List<JifenReq> jifens = new ArrayList<>();
            if(CollectionUtils.size(dataList) > 0){
                dataList.stream().forEach(jifenReqEntity -> {
                    JifenReq req = new JifenReq();
                    BeanUtils.copyProperties(jifenReqEntity, req);
                    if(jifenReqEntity.getOwner() != null){
                        req.setMobile(jifenReqEntity.getUser().getUsername());
                        req.setPlatform(jifenReqEntity.getUser().getPlatform());
                    }
                    if(jifenReqEntity.getUser_req() != null){
                        req.setMobile(jifenReqEntity.getUser_req().getUsername());
                    }
                    jifens.add(req);
                });
            }
            response.setStatus(Status.SUCCESS);
            response.setRows(jifens);
            response.setTotal(page.getTotalElements());
        } catch (Exception e) {
            response.setStatus(Status.FAILED);
            response.setMessage(e.getMessage());
            log.error("error", e);
        }
        return response;
    }

    @Override
    public GeneralResponse saveAndFlush(JifenReq jifen, UserEntity owner , String description) {
        GeneralResponse response = new GeneralResponse();
        try{
        } catch(Exception e){
            response.setMessage(e.getMessage());
            response.setStatus(Status.FAILED);
        }
        return response;
    }

    @Override
    public List<JifenReqEntity> findByMobiles(String mobiles) throws Exception {
        List<String> list = new ArrayList<>();
        if(StringUtil.format(mobiles).equals("")){
            throw new Exception("参数错误");
        }
        String[] strs = mobiles.split(",");
        for(String mobile: strs){
            list.add(mobile);
        }
        return repository.findByMobiles(list);
    }

    @Override
    public List<JifenReqEntity> findByIds(String ids) throws Exception {
        List<Long> list = new ArrayList<>();
        if(StringUtil.format(ids).equals("")){
            throw new Exception("参数错误");
        }
        String[] strs = ids.split(",");
        for(String id: strs){
            if(!StringUtil.isEmpty(id)){
                list.add(Long.parseLong(id));
            }
        }
        return repository.findByIds(list);
    }

    @Override
    public GeneralResponse sent(String ids) {
        GeneralResponse response = new GeneralResponse();
        try{
            if(StringUtil.isEmpty(ids)){
                throw new Exception("参数错误");
            }
            List<JifenReqEntity> jifenReqEntities = findByIds(ids);
            if(CollectionUtils.size(jifenReqEntities) > 0){
                jifenReqEntities.stream().forEach(jifenReq -> {
                    if(jifenReq.getUser_req() != null){
                        JifenEntity jifenEntity = jifenService.findByUsername(jifenReq.getUser_req().getUsername());
                        UserEntity u = jifenReq.getUser_req();
                        MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
                        map.add("jifen", jifenReq.getReq_jifen().toString());
                        map.add("adminId", jifenReq.getUser_req().getUsername());
                        String resultJson = null;
                        if(jifenEntity == null){
                            map.add("total", jifenReq.getReq_jifen().toString());
                            try {
                                resultJson = (String) restService.postForEntity(globalConfiguration.getEthereumUrl() + "jifen/save", map);
                                JSONObject obj = JSONObject.parseObject(resultJson);
                                if (obj.getString("status").equals("SUCCESS")) {
                                    jifenEntity = new JifenEntity();
                                    jifenEntity.setJifen(jifenReq.getReq_jifen().toString());
                                    jifenEntity.setUser(jifenReq.getUser_req());
                                    jifenEntity.setTotal(jifenReq.getReq_jifen().toString());
                                    jifenEntity.setTransactionHash(JSONObject.parseObject(obj.getString("data")).getString("transactionHash"));
                                    jifenRepository.save(jifenEntity);
                                    saveStream(jifenReq.getReq_jifen().toString(), jifenReq.getReq_jifen().toString()
                                            , jifenReq.getUser_req(), "批量审核积分", jifenEntity.getTransactionHash());
                                    u.setJifen(jifenReq.getReq_jifen().intValue());
                                } else {
                                    response.setMessage(obj.getString("message"));
                                    response.setStatus(Status.FAILED);
                                }
                            } catch (Exception e) {
                                e.printStackTrace();
                                log.error(e.getMessage());
                            }

                        } else {
                            BigDecimal cur = new BigDecimal(StringUtil.format(jifenEntity.getJifen()).equals("") ? "" : jifenEntity.getJifen());
                            cur = cur.add(jifenReq.getReq_jifen());
                            map.add("total", cur.toString());
                            try {
                                resultJson = (String) restService.postForEntity(globalConfiguration.getEthereumUrl() + "jifen/save", map);
                                JSONObject obj = JSONObject.parseObject(resultJson);
                                if (obj.getString("status").equals("SUCCESS")) {
                                    jifenEntity.setJifen(jifenReq.getReq_jifen().toString());
                                    jifenEntity.setUser(jifenReq.getUser_req());
                                    jifenEntity.setTotal(cur.toString());
                                    jifenEntity.setTransactionHash(JSONObject.parseObject(obj.getString("data")).getString("transactionHash"));
                                    jifenRepository.saveAndFlush(jifenEntity);
                                    saveStream(jifenReq.getReq_jifen().toString(), cur.toString()
                                            , jifenReq.getUser_req(), "批量审核积分", jifenEntity.getTransactionHash());
                                    u.setJifen(cur.intValue());
                                } else {
                                    response.setMessage(obj.getString("message"));
                                    response.setStatus(Status.FAILED);
                                }
                            } catch (Exception e) {
                                e.printStackTrace();
                                log.error(e.getMessage());
                            }
                        }
                        userRepository.saveAndFlush(u);
                        jifenReq.setStatus("OK");
                        repository.save(jifenReq);
                    }
                });
            }
        } catch(Exception e){
            response.setMessage(e.getMessage());
            response.setStatus(Status.FAILED);
        }
        return response;
    }

    private void saveStream(String jifen, String total, UserEntity user, String description, String transactionHash) throws Exception{
        JifenStreamEntity entity = new JifenStreamEntity();
        entity.setJifen(jifen);
        entity.setTotal(total);
        entity.setDescription(description);
        entity.setUser(user);
        entity.setTransactionHash(transactionHash);
        jifenStreamRepository.save(entity);
    }

    @Override
    public GeneralResponse setExchangeRate(UserEntity user) {
        GeneralResponse response = new GeneralResponse();
        try{
            userRepository.saveAndFlush(user);
            response.setStatus(Status.SUCCESS);
        } catch(Exception e){
            response.setStatus(Status.FAILED);
            response.setMessage(e.getMessage());
        }
        return response;
    }

    @Override
    public GeneralResponse jifenBuy(UserEntity user, String category, String jifen_num) {
        GeneralResponse response = new GeneralResponse();
        try{
            JifenReqEntity req = new JifenReqEntity();
            req.setPlatform(category);
            req.setReq_jifen(new BigDecimal(jifen_num));
            req.setJifen(new BigDecimal(user.getJifen()== null ? "0" : user.getJifen()+""));
            req.setUser_req(user);
            req.setDescription("积分购买");
            jifenReqRepository.save(req);
        } catch (Exception e){
            response.setStatus(Status.FAILED);
            response.setMessage(e.getMessage());
        }
        return response;
    }

}
